<script setup>
import { nextTick } from 'vue'

const props = defineProps({
  list: {
    type: Array,
    default: () => [],
  },
  speed: {
    type: Number,
    default: 0.1,
  },
  // 滚动作单步运动时的单纯运动距离
  singleHeight: {
    type: Number,
    default: 0,
  },
  // 单步运动的时间间隔
  waitTime: {
    type: Number,
    default: 0,
  },
  grid: {
    type: String,
    default: '',
  },
})

const scrollBox = ref(null)
const scrollItemBox = ref(null)
const outer = ref(null)

const data = reactive({
  rafId: null,
  y: 0,
  showSecond: false,
  controleHeight: 0,
  animeRequest: null,
  realSpeed: 0,
  timer: null,
})

const reqAnimationFrame = () => {
  // 滚动速度
  data.speed = data.speed > 1 ? 1 : data.speed < 0 ? 0.1 : data.speed

  // 取第一个scrollItemBox高度
  const definedHeight = getComputedHeight(scrollItemBox.value)
  // 持续滚动
  data.y = data.y + data.speed
  scrollBox.value.style.top = `${-data.y}px`

  // ====添加滚动间隔控制====开始
  if(props.singleHeight >= 20 && props.waitTime > 500) {
    if(data.controleHeight >= props.singleHeight) {
      cancelAnimationFrame(data.animeRequest)
      data.controleHeight = 0
      data.timer = setTimeout(() => {
        if(canRun()) { // @fixme
          reqAnimationFrame()
        }
      }, props.waitTime)
      return
    }
    else {
      // 一次移动高度未达到指定距离继续执行动画
      data.controleHeight += data.speed
    }
  }
  // ====添加滚动间隔控制====结束

  // 当滚动到第一个scroll-item-box高度时scrollBox重置为top:0,视觉上是无缝滚动
  if(data.y >= definedHeight) {
    data.y = 0
  }
  data.animeRequest = window.requestAnimationFrame(reqAnimationFrame)
}

watch(() => props.list, (newVal) => {
  nextTick(() => {
    console.log(newVal)
    if(newVal?.length) {
      if(data.animeRequest) {
        cancelAnimationFrame(data.animeRequest)
      }
      // 开启动画
      if(canRun()) {
        reqAnimationFrame()
      }
      // this.reqAnimationFrame();
      // 手动滚动到底部时滚动条重置到最上边,同时滚动盒子重置为top:0
      outer.value.addEventListener('scroll', () => {
        if(
          outer.value.scrollTop + outer.value.clientHeight + 4
          >= outer.value.scrollHeight
        ) {
          outer.value.scrollTop = 0
          data.y = 0
          scrollBox.value.style.top = 0
        }
      })
    }
  })
}, { deep: true, immediate: true })

const canRun = () => {
  // 开启动画条件：滚动盒子(scrollBox)高度高于外层容器(outer)高度
  if(outer.value?.offsetHeight >= scrollItemBox.value?.offsetHeight) {
    data.showSecond = false
    outer.value.scrollTop = 0
    data.y = 0
    scrollBox.value.style.top = 0
    return false
  }
  else {
    data.showSecond = true
    return true
  }
}

const listenResizeFn = () => {
  cancelAnimationFrame(data.animeRequest)
  if(canRun()) {
    reqAnimationFrame()
  }
}

const onMouseover = () => {
  clearTimeout(data.timer)
  cancelAnimationFrame(data.animeRequest)
}

const onMouseleave = () => {
  if(canRun()) {
    reqAnimationFrame()
  }
}

// 获取dom元素的高度：content+padding+margin+border
const getComputedHeight = (dom) => {
  const computedStyle = getComputedStyle(dom)

  const computedHeight
        = dom.offsetHeight
        + parseFloat(computedStyle.marginTop)
        + parseFloat(computedStyle.marginBottom)
  return computedHeight
}

onMounted(() => {
  data.speed = props.speed > 1 ? 1 : props.speed < 0 ? 0.1 : props.speed
  window.addEventListener('resize', listenResizeFn)
})

onBeforeUnmount(() => {
  window.removeEventListener('resize', listenResizeFn)
  cancelAnimationFrame(data.animeRequest)
  if(data.timer) {
    clearTimeout(data.timer)
  }
})

const { showSecond } = toRefs(data)
</script>

<template>
  <div ref="outer" class="scroll-outer" @mouseover="onMouseover" @mouseleave="onMouseleave">
    <div ref="scrollBox" class="scroll-inner-box">
      <div ref="scrollItemBox" class="scroll-item-box" :class="grid && `grid-${grid}`">
        <slot />
      </div>
      <div v-if="showSecond" class="scroll-item-box" :class="grid && `grid-${grid}`">
        <slot />
      </div>
    </div>
  </div>
</template>

  <style lang="scss">
.scroll-outer {
  position: relative;
  height: 100%;
  overflow-x: hidden;

  &::-webkit-scrollbar {
    width: 0.3vw;
  }

  &:hover::-webkit-scrollbar-track {
    background-color: #295099;
    border-radius: 0.1vw;
    box-shadow: inset 0 0 0.1vw rgb(0 0 0 / 30%);
    opacity: 1;
    // display: none;
  }

  &:hover::-webkit-scrollbar-thumb {
    background-color: #0ba9ea;
    border-radius: 0.1vw;
    box-shadow: inset 0 0 0.1vw rgb(0 0 0 / 30%);
    opacity: 1;
  }
}

.scroll-inner-box {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: auto;
}

.scroll-item-box {
  &.grid-2 {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 20px;
  }
}
</style>
